
// 服务器端
// 基于HTTP协议
#include "http.hpp"
#include <sys/wait.h>

// 缓冲区大小
#define BUFFER_SIZE 4096

// 定义一个回调方法，处理请求
void handle_request(int sockfd)
{
    char buffer[BUFFER_SIZE];
    // 读取请求报文
    ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1,0);
    if (n > 0)
    {
        buffer[n] = 0;
        //for debug
        //std::cout<<buffer<<std::endl;
        
        Request req;
        // 将读取到的字符串反序列为请求对象
        req.Deserilaze(buffer);


        // 构建应答报文
        Response resp;
        //获取客户端想要访问的资源文件
        resp.SetTargetFile(req.GetUri());

        //for debug
        //std::cout<<"##############################"<<std::endl;
        //std::cout<<req.GetUri()<<std::endl;
        //std::cout<<"##############################"<<std::endl;

        // 将目标文件内容填写到正问部分
        resp.SetText();
        resp._version = "HTTP/1.1";
        resp._code = 200; // success
        resp._desc = "OK";
        // 反序列化
        std::string resp_str = resp.Serilaze();
        // 发送应答报文
        send(sockfd, resp_str.c_str(), resp_str.size(),0);
    }
}
const int gbacklog = 8;
int main(int argc, char *argv[])
{
    // 1,创建套接字
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd < 0)
    {
        std::cerr << "创建监听套接字失败" << std::endl;
        exit(1);
    }
    // 从命令行参数中获取端口号
    uint16_t port = std::stoi(argv[1]);

    // 填写sockaddr_in结构体，注意主机序列转化为网络字节序
    struct sockaddr_in addr;
    int addrlen = sizeof(addr);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;

    // 2,绑定端口号和ip地址
    int n = bind(listenfd, (struct sockaddr *)&addr, sizeof(addr));
    if (n < 0)
    {
        std::cerr << "绑定失败" << std::endl;
        exit(2);
    }
    // 3,开始监听
    int s = listen(listenfd, gbacklog);
    if (s < 0)
    {
        std::cerr << "监听失败" << std::endl;
        exit(3);
    }
    // 4，获取连接，处理连接
    while (true)
    {
        int sockfd = accept(listenfd, (struct sockaddr *)&addr, (socklen_t *)&addrlen);
        if (n < 0)
        {
            std::cerr << "获取连接失败" << std::endl;
            continue; // 继续获取
        }
        // 创建子进程处理请求
        pid_t id = fork();
        if (id == 0)
        {
            // 子进程
            // 关闭不需要的文件描述符
            close(listenfd);
            if (fork() > 0)
                exit(0); // 子进程退出

            // 孙子进程 处理请求
            handle_request(sockfd);
            // 孙子进程退出
            exit(0);
        }
        else if (id > 0)
        {
            // 父进程
            // 关闭不需要的文件描述符
            close(sockfd);
            pid_t rid=::waitpid(id,nullptr,0);
            (void)rid;
        }
        else
        {
            std::cerr << "创建子进程失败" << std::endl;
        }
    }
    return 0;
}